'''
Created on May 7, 2011

@author: james

In a two week period patients should have continuity of care, prefer that same doctor is on call for that time period
applies to NICU service and step-down service
'''

from Doctors import Doctors

class TwoWeekServiceCycleEvaluator():
    
    def __init__(self, nicuIndex, stepDownIndex, weekBoundary, rota, initCount, multiplier):
        self._nicuIndex = nicuIndex
        self._stepDownIndex = stepDownIndex
        self._nicuCalls = rota['nicu']
        self._stepDownCalls = rota['sd']
        self._initCount = initCount
        self._weekBoundary = weekBoundary
        self._multiplier = multiplier
    
    def findDoctorOnService(self, counts):
        max_value = 0
        doctorOnService = -1
        count = 0
        
        for key, value in counts.items():
            count += value
            if value > max_value: 
                max_value = value
                doctorOnService = key
                
        return doctorOnService

    def evaluate(self, chromosome, debug = False):
        '''
        prefer that same doctor be on service for two week cycle
        '''
        score = self.evaluateTwoWeekService(chromosome, self._nicuIndex, self._nicuCalls, debug)
        score += self.evaluateTwoWeekService(chromosome, self._stepDownIndex, self._stepDownCalls, debug)
        score *= self._multiplier
        
        if debug: print "TwoWeekServiceCycleEvaluator score: %d" % score
        return score
        
    def evaluateTwoWeekService(self, chromosome, serviceIndex, doctorContinuingService, debug = False):
        '''
        evaluation constraint for service type
        currently does not calculate doctor on service to carry over to next month
        max score is number of calls in month
        '''
        
        score = 0
        weekNo = 0
        output = ""
        
        counts = self._initCount.copy()
        
        for index in serviceIndex:
            
            score += 1
            
            if weekNo < len(self._weekBoundary) and index > self._weekBoundary[weekNo]:
                weekNo += 1
                
                score -= self.evaluateServiceCounts(weekNo, doctorContinuingService, counts, output, debug)                    
                counts = self._initCount.copy()
                output = ""
            
            doctor = chromosome[index]
            counts[doctor] += 1
            output += "%s " % (Doctors().doctorNames[doctor])

        score -= self.evaluateServiceCounts(weekNo + 1, doctorContinuingService, counts, output, debug)
        
        if debug: print "Score: %d" % score
        
        return score
    
    def evaluateServiceCounts(self, weekNo, doctorContinuingService, counts, output, debug):
        '''
        works out the score for this series of service calls
        note that we have to return positive number since we subtract in the use of return value
        '''
        score = 0
        
        #print "%s, %d" % (doctorContinuingService, weekNo)
        #doctorOnService = self.findDoctorOnService(counts)
        doctorOnService = doctorContinuingService[weekNo - 1]
                    
        # if this is the first week and we need to continue two week shift
        #if weekNo == 1 and doctorContinuingService != -1:
        #    doctorOnService = doctorContinuingService
                        
        for key, value in counts.items():
            # penalty is sum of those days when other doctor has to cover
            if key != doctorOnService: score -= value
        
        if debug: print "Week no. %d service: '%s', %s" % (weekNo, Doctors().doctorNames[doctorOnService], output)

        return -score
    
    def evaluateConvergenceCriteria(self, chromosome, attempt):
        
        maxScore = (len(self._nicuIndex) + len(self._stepDownIndex)) * self._multiplier
        
        score = self.evaluate(chromosome)
         
        return score / float(maxScore) > (1 - (float(attempt) / 10))

